﻿using System;
using System.Windows.Forms;
using MathNet.Numerics;
using MathNet.Numerics.Distributions;
using MentalAlchemy.Molecules;

namespace MentalAlchemy.Compounds
{
	// todo: make edit button functionality for editing polynomial coefs with several presets for lacunary pols.
	public partial class RandomPolynomialControl : UserControl
	{
		protected Polynomial pol;
		protected Complex[] cPol;

		#region - Properties. -
		//public Polynomial Polynomial
		//{
		//    get
		//    {
		//        var name = (string)PolNameCombo.SelectedItem;
		//        pol = RandomPolynomialElements.CreateRandomPolynomial(name, Order);
		//        return pol;
		//    }
		//    set { pol = value;}
		//}
		//public Complex[] ComplexPolynomial
		//{
		//    get
		//    {
		//        var name = (string)PolNameCombo.SelectedItem;
		//        cPol = RandomPolynomialElements.CreateRandomComplexPolynomial(name, Order);
		//        return cPol;
		//    }
		//    set { cPol = value;}
		//}
		public Polynomial Polynomial
		{
			get; set;
		}
		public Complex[] ComplexPolynomial
		{
			get; set;
		}
		public int Order
		{
			get { return (int)OrderNumeric.Value; }
			set { OrderNumeric.Value = value;}
		}
		public bool IsComplex
		{
			get { return ComplexCheck.Checked; }
			set { ComplexCheck.Checked = value; }
		}
		public string PolynomialName
		{
			get { return (string) PolNameCombo.SelectedItem; }
		}
		#endregion

		public RandomPolynomialControl()
		{
			InitializeComponent();

			Polynomial = new Polynomial((int)OrderNumeric.Value);
			ComplexPolynomial = new Complex[(int)OrderNumeric.Value];

			// Init pols list combo.
			var pols = Polynomials.GetRandomPolynomials();
			foreach (var pol in pols)
			{
				PolNameCombo.Items.Add(pol);
			}
			PolNameCombo.SelectedIndex = 0;
		}

		private void GenerateBtn_Click(object sender, EventArgs e)
		{
			Generate();
		}

		public Polynomial Generate ()
		{
			var name = (string)PolNameCombo.SelectedItem;
			if (IsComplex)
			{
				ComplexPolynomial = RandomPolynomialElements.CreateRandomComplexPolynomial(name, Order);
				Polynomial = null;
			}
			else
			{
				Polynomial = RandomPolynomialElements.CreateRandomPolynomial(name, Order);
				ComplexPolynomial = null;
			}
			Parent.BringToFront();
			return null;
		}
	}

	public class RandomPolynomialElements
	{
		/// <summary>
		/// [compounds]
		/// 
		/// Creates random polynomial of the given orders.
		/// </summary>
		/// <param name="polName"></param>
		/// <param name="order"></param>
		/// <returns></returns>
		public static Polynomial CreateRandomPolynomial(string polName, int order)
		{
			RandomDistribution distr = GetCoefficientsDistribution(polName);
			return Polynomials.GetPolynomial(polName, order, distr);
		}

		public static Complex[] CreateRandomComplexPolynomial(string polName, int order)
		{
			RandomDistribution distr = GetCoefficientsDistribution(polName);
			return Polynomials.GetComplexPolynomial(polName, order, distr);
		}

		/// <summary>
		/// [molecule]
		/// 
		/// Returns random distribution for generation of coefficients for a polynomial of prescribed type.
		/// </summary>
		/// <returns></returns>
		public static RandomDistribution GetCoefficientsDistribution(string polName)
		{
			RandomDistribution distr = null;
			if (polName == Polynomials.RANDOM_POL_POISSON)
			{
				distr = Utils.GetPoissonDistribution();
			}
			else if (polName == Polynomials.RANDOM_POL_GAUSSIAN)
			{
				distr = Utils.GetGaussianDistribution();
			}
			else if (polName == Polynomials.RANDOM_POL_GEOMETRIC)
			{
				distr = Utils.GetGeometricDistribution();
			}
			else if (polName == Polynomials.RANDOM_POL_UNIFORM)
			{
				distr = Utils.GetUniformDistribution();
			}
			else if (polName == Polynomials.RANDOM_POL_UNIFORM_1 || polName == Polynomials.BERNSTEIN_POL)
			{
				//var sigma = 1.0/Math.Sqrt(3);	// sigma value for [-1; +1] interval. sigma = (b-a)/(2*sqrt{3})
				var cDistr = new ContinuousRandomDistribution();
				cDistr.Distribution = new ContinuousUniformDistribution(-1 + double.Epsilon, 1 - double.Epsilon);	// in order to exclude boundary values.
				distr = cDistr;
			}
			else
			{	// use Gaussian distribution by default.
				distr = Utils.GetGaussianDistribution();
			}
			return distr;
		}
	}
}
